package vca;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import jenes.chromosome.IntegerChromosome;

import org.jgrapht.UndirectedGraph;
import org.jgrapht.alg.ConnectivityInspector;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.SimpleGraph;

public class GraphManager {

	public UndirectedGraph<Point, DefaultEdge> graph;
	public ArrayList<Point> dirtyTiles;
	public Point base;
	public Point agentPos;
	public int matrixSize;
	public int initalCleanTiles;

	public GraphManager(int[][] m, ArrayList<Point> dt, Point base,
			Point agentPos) {

		dirtyTiles = dt;

		this.agentPos = agentPos;

		matrixSize = m[0].length;

		initalCleanTiles = matrixSize * matrixSize - dirtyTiles.size();

		graph = new SimpleGraph<>(DefaultEdge.class);

		this.base = base;

		for (int i = 0; i < m[0].length; i++)
			for (int j = 0; j < m[0].length; j++)
				if (m[i][j] != Enviroment.OBSTACLE)
					graph.addVertex(new Point(i, j));

		for (Point p : graph.vertexSet())
			for (Point p1 : graph.vertexSet())
				if (Math.abs(p.x - p1.x) + Math.abs(p.y - p1.y) == 1)
					graph.addEdge(p, p1);
	}


	public boolean baseIsReachable(){
		ConnectivityInspector<Point, DefaultEdge> ci = new ConnectivityInspector<>(
				graph);
		return ci.pathExists(agentPos, base);
	}
	
	public int pruneDirtyNodes() {

		ConnectivityInspector<Point, DefaultEdge> ci = new ConnectivityInspector<>(
				graph);

		ArrayList<Point> remainingDirtyNodes = new ArrayList<>();
		for (int i = 0; i < dirtyTiles.size(); i++)
			if (ci.pathExists(agentPos, dirtyTiles.get(i)))
				remainingDirtyNodes.add(dirtyTiles.get(i));

		dirtyTiles = remainingDirtyNodes;

		return dirtyTiles.size();
	}

	public int computeDistance(ArrayList<Integer> individual) {

		ArrayList<Point> path = new ArrayList<Point>();

		path.add(agentPos);

		for (int i = 0; i < individual.size(); i++)
			if (individual.get(i) != -1)
				path.add(dirtyTiles.get(individual.get(i)));

		path.add(base);

		int distance = 0;

		for (int i = 0; i < path.size() - 1; i++) {
			List l = DijkstraShortestPath.findPathBetween(graph, path.get(i),
					path.get(i + 1));
			if (l != null)
				distance += l.size();
		}
		return distance;
	}

	public ArrayList<Point> computePath(ArrayList<Integer> individual) {

		ArrayList<Point> solution = new ArrayList<>();
		ArrayList<Point> path = new ArrayList<Point>();

		path.add(agentPos);

		for (int i = 0; i < individual.size(); i++)
			if (individual.get(i) != -1)
				path.add(dirtyTiles.get(individual.get(i)));

		path.add(base);

		solution.add(agentPos);
		Point cur = new Point(agentPos.x, agentPos.y);
		for (int i = 0; i < path.size() - 1; i++) {
			List<DefaultEdge> l = DijkstraShortestPath.findPathBetween(graph,
					path.get(i), path.get(i + 1));
			if (l != null) {
				for (DefaultEdge e : l) {
					if (cur.equals(graph.getEdgeSource(e))) {
						solution.add(graph.getEdgeTarget(e));
						cur = graph.getEdgeTarget(e);
					} else {
						solution.add(graph.getEdgeSource(e));
						cur = graph.getEdgeSource(e);
					}
					// System.out.println(cur);
				}

			}

		}
		// solution.add(base);
		// System.out.println(path);
		// System.out.println(solution);
		return solution;
	}

}
